package cn.chenhuanming.shh.authentication.server.security;

import org.jooq.DSLContext;
import org.jooq.Record1;
import org.jooq.Record2;
import org.jooq.Record3;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.List;

import static cn.chenhuanming.shh.authentication.server.entity.house.Tables.*;

/**
 * Created by chenhuanming on 2017-07-14.
 *
 * @author chenhuanming
 */
@Service
public class UserServiceDetails implements UserDetailsService {

    private final String ROLE_PREFIX = "ROLE_";
    private final String BROKER_ROLE_ID = "ROLE_SHOP_BROKER";

    private final String ROLE_STATE_START = "启用";

    @Autowired
    DSLContext create;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //throw exception when username is empty
        if (StringUtils.isEmpty(username))
            throw new UsernameNotFoundException(username);

        //check whether user is broker
        Record2<String, String> userBroker =
                create.select(USER_BROKER.USERNAME, USER_BROKER.PASSWORD)
                        .from(USER_BROKER)
                        .where(USER_BROKER.USERNAME.eq(username)).fetchOne();

        //check whether user is userSystem,while is not broker
        if (userBroker != null) {
            if (isStarted(BROKER_ROLE_ID))
                throw new DisabledException(username);
            return new User(username, userBroker.get(USER_BROKER.PASSWORD), getRoles(userBroker));
        } else {
            Record3<String, String, String> userSystem =
                    create.select(USER_SYSTEM.USERNAME, USER_SYSTEM.PASSWORD, USER_SYSTEM.ROLE_ID)
                            .from(USER_SYSTEM)
                            .where(USER_SYSTEM.USERNAME.eq(username)).fetchOne();
            if (userSystem == null)
                throw new UsernameNotFoundException(username);
            if (isStarted(userSystem.get(USER_SYSTEM.ROLE_ID)))
                throw new DisabledException(username);
            else
                return new User(username, userSystem.getValue(USER_SYSTEM.PASSWORD), getRoles(userSystem));
        }
    }

    private List<GrantedAuthority> getRoles(Record2<String, String> userBroker) {
        Record1<String> userRole = create
                .select(USER_ROLE.NAME)
                .from(USER_ROLE)
                .where(USER_ROLE.ID.eq(BROKER_ROLE_ID)).fetchOne();
        if (userRole == null)
            throw new IllegalStateException("经纪人角色应该为" + BROKER_ROLE_ID);
        else
            return Arrays.asList(new SimpleGrantedAuthority(BROKER_ROLE_ID));
    }

    private List<GrantedAuthority> getRoles(Record3<String, String, String> userSystem) {
        String roleID = userSystem.get(USER_SYSTEM.ROLE_ID);
        if (!roleID.startsWith(ROLE_PREFIX))
            roleID = ROLE_PREFIX + roleID;
        return Arrays.asList(new SimpleGrantedAuthority(roleID));
    }

    private boolean isStarted(String roleID) {
        Record1<String> status = create.select(USER_ROLE.STATUS).from(USER_ROLE).where(USER_ROLE.ID.eq(roleID)).fetchOne();
        return status.equals(ROLE_STATE_START) ? true : false;
    }
}
